/*
 This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU Affero General Public License as published by the Free
 Software Foundation; either version 3 of the License, or (at your option) any
 later version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License along
 with this program; if not, see http://www.gnu.org/licenses or write to the Free
 Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 */
package com.ojoin.trade.common.utils.file;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Helper class to get mimetype
 * 
 * @author jcompagner
 */
@SuppressWarnings("nls")
public class MimeTypes
{
	private static Logger logger = LoggerFactory
			.getLogger(MimeTypes.class);

	
	public static String getContentType(byte[] data)
	{
		return getContentType(data, null);
	}

	public static String getContentType(byte[] data, String name)
	{
		if (data == null)
		{
			return null;
		}
		byte[] header = new byte[11];
		System.arraycopy(data, 0, header, 0, Math.min(data.length, header.length));
		int c1 = header[0] & 0xff;
		int c2 = header[1] & 0xff;
		int c3 = header[2] & 0xff;
		int c4 = header[3] & 0xff;
		int c5 = header[4] & 0xff;
		int c6 = header[5] & 0xff;
		int c7 = header[6] & 0xff;
		int c8 = header[7] & 0xff;
		int c9 = header[8] & 0xff;
		int c10 = header[9] & 0xff;
		int c11 = header[10] & 0xff;

		if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE)
		{
			return "application/java-vm";
		}

		if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 && c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1)
		{
			// if the name is set then check if it can be validated by name, because it could be a xls or powerpoint
			String contentType = guessContentTypeFromName(name);
			if (contentType != null)
			{
				return contentType;
			}
			return "application/msword";
		}
		if (c1 == 0x25 && c2 == 0x50 && c3 == 0x44 && c4 == 0x46 && c5 == 0x2d && c6 == 0x31 && c7 == 0x2e)
		{
			return "application/pdf";
		}

		if (c1 == 0x38 && c2 == 0x42 && c3 == 0x50 && c4 == 0x53 && c5 == 0x00 && c6 == 0x01)
		{
			return "image/photoshop";
		}

		if (c1 == 0x25 && c2 == 0x21 && c3 == 0x50 && c4 == 0x53)
		{
			return "application/postscript";
		}

		if (c1 == 0xff && c2 == 0xfb && c3 == 0x30)
		{
			return "audio/mp3";
		}

		if (c1 == 0x49 && c2 == 0x44 && c3 == 0x33)
		{
			return "audio/mp3";
		}

		if (c1 == 0xAC && c2 == 0xED)
		{
			// next two bytes are version number, currently 0x00 0x05
			return "application/x-java-serialized-object";
		}

		if (c1 == '<')
		{
			if (c2 == '!' ||
				((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' || c3 == 'e' && c4 == 'a' && c5 == 'd') || (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) ||
				((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' || c3 == 'E' && c4 == 'A' && c5 == 'D') || (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y'))))
			{
				return "text/html";
			}

			if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ')
			{
				return "application/xml";
			}
		}

		// big and little endian UTF-16 encodings, with byte order mark
		if (c1 == 0xfe && c2 == 0xff)
		{
			if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' && c7 == 0 && c8 == 'x')
			{
				return "application/xml";
			}
		}

		if (c1 == 0xff && c2 == 0xfe)
		{
			if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 && c7 == 'x' && c8 == 0)
			{
				return "application/xml";
			}
		}

		if (c1 == 'B' && c2 == 'M')
		{
			return "image/bmp";
		}

		if (c1 == 0x49 && c2 == 0x49 && c3 == 0x2a && c4 == 0x00)
		{
			return "image/tiff";
		}

		if (c1 == 0x4D && c2 == 0x4D && c3 == 0x00 && c4 == 0x2a)
		{
			return "image/tiff";
		}

		if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8')
		{
			return "image/gif";
		}

		if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f')
		{
			return "image/x-bitmap";
		}

		if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' && c5 == 'M' && c6 == '2')
		{
			return "image/x-pixmap";
		}

		if (c1 == 137 && c2 == 80 && c3 == 78 && c4 == 71 && c5 == 13 && c6 == 10 && c7 == 26 && c8 == 10)
		{
			return "image/png";
		}

		if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF)
		{
			if (c4 == 0xE0)
			{
				return "image/jpeg";
			}

			/**
			 * File format used by digital cameras to store images. Exif Format can be read by any application supporting JPEG. Exif Spec can be found at:
			 * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF
			 */
			if ((c4 == 0xE1) && (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 == 'f' && c11 == 0))
			{
				return "image/jpeg";
			}

			if (c4 == 0xEE)
			{
				return "image/jpg";
			}
		}

		/**
		 * According to http://www.opendesign.com/files/guestdownloads/OpenDesign_Specification_for_.dwg_files.pdf
		 * first 6 bytes are of type "AC1018" (for example) and the next 5 bytes are 0x00.
		 */
		if ((c1 == 0x41 && c2 == 0x43) && (c7 == 0x00 && c8 == 0x00 && c9 == 0x00 && c10 == 0x00 && c11 == 0x00))
		{
			return "application/acad";
		}

		if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64)
		{
			return "audio/basic"; // .au
			// format,
			// big
			// endian
		}

		if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E)
		{
			return "audio/basic"; // .au
			// format,
			// little
			// endian
		}

		if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F')
		{
			/*
			 * I don't know if this is official but evidence suggests that .wav files start with "RIFF" - brown
			 */
			return "audio/x-wav";
		}

		if (c1 == 'P' && c2 == 'K')
		{
			// its application/zip but this could be a open office thing if name is given
			String contentType = guessContentTypeFromName(name);
			if (contentType != null)
			{
				return contentType;
			}
			return "application/zip";
		}
		return guessContentTypeFromName(name);
	}

	private static final Map<String, String> mimeTypes = new HashMap<String, String>();

	public static String guessContentTypeFromName(String name)
	{
		if (name == null) return null;

		int lastIndex = name.lastIndexOf('.');
		if (lastIndex != -1)
		{
			String extention = name.substring(lastIndex + 1).toLowerCase();
			if (mimeTypes.size() == 0)
			{
				HashMap<String, String> tempMap = new HashMap<String, String>();
				InputStream is = MimeTypes.class.getResourceAsStream("/mime.types.properties");
				try
				{
					Properties properties = new Properties();
					properties.load(is);
					for (Object key : properties.keySet())
					{
						String property = properties.getProperty((String)key);
						StringTokenizer st = new StringTokenizer(property, " ");
						while (st.hasMoreTokens())
						{
							tempMap.put(st.nextToken(), (String)key);
						}
					}
				}
				catch (IOException e)
				{
					logger.error("MimeType",e);
				}
				finally
				{
					try
					{
						is.close();
					}
					catch (IOException e)
					{
						logger.error("MimeType",e);
					}
				}
				synchronized (mimeTypes)
				{
					mimeTypes.putAll(tempMap);
				}
			}
			return mimeTypes.get(extention);
		}
		return null;
	}
}